home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / cug106 / stdlib2.c < prev    next >
C/C++ Source or Header  |  1984-06-14  |  10KB  |  373 lines

  1. /*    ---------------------------------------------------------
  2.     Mods by H Moran:
  3.  
  4.     In case you wish to adopt some but not all of the mods:
  5.     Lines modified by HRM marked with comment 'HRM mod'
  6.     Lines added by HRM marked with comment 'HRM'
  7.  
  8.  
  9.     1) added functions: for list reader and punch devices
  10.  
  11.         lprintf pprintf        -- list and punch devices
  12.         rscanf            -- reader device
  13.         rgets            -- reader device
  14.         lputs   pputs        -- list and punch devices
  15.         lputc   pputc        -- list and punch devices
  16.         rgetc            -- reader device
  17.  
  18.     2) sprintf() modified to use '0' for left fill char
  19.        when radix is not decimal.
  20.  
  21.     3) binary field spec added to sprintf() and sscanf()
  22.        spec used is %b
  23.  
  24.     4) pad char for non-decimal numeric fields in sprintf()
  25.        changed to '0'
  26.  
  27.     5) printing of a..f changed to A..F in _uspr()
  28.  
  29.     6) fgets() fixed to remember reception of 0x1a
  30.        and handle it as EOF. See the one caveat in
  31.        the modified comments.
  32.     -------------------------------------------------------
  33. */
  34.  
  35. /*
  36.     This file contains the source for the following
  37.     library functions:
  38.  
  39.     printf **    fprintf    **    sprintf *
  40.     scanf        fscanf        sscanf
  41.     gets        fgets
  42.     puts        fputs
  43.     swapin ***
  44.  
  45.     *) rewritten for 1.31
  46.     **) work differently since they use the new "sprintf"
  47.     ***) brand new for 1.31
  48.  
  49.     An alternate version of "sprintf" is given in the file
  50.     FLOAT.C for use with floating point numbers; see FLOAT.C
  51.     for details. Note that "sprintf" is used by "printf", so
  52.     this really amounts to an alternate version of "printf",
  53.     too.
  54.  
  55.     Note that all the upper-level formatted I/O functions
  56.     ("printf", "fprintf", "scanf", and "fscanf") now use
  57.     "sprintf" and "sscanf" for doing conversions. While
  58.     this leads to very structured source code, it also
  59.     means that calls to "scanf" and "fscanf" must process
  60.     ALL the information on a line of text; if the format
  61.     string runs out and there is still text left in the
  62.     line being processed, the text will be lost (i.e., the
  63.     NEXT scanf or fscanf call will NOT find it.)
  64.  
  65.     Also note that temporary work space is declared within
  66.     each of the high-level functions as a one-dimensional
  67.     character array. The length limit on this array is
  68.     presently set to 132 by the #define MAXLINE statement;
  69.     if you intend to create longer lines through printf,
  70.     fprintf, scanf, or fscanf calls, be SURE to raise this
  71.     limit by changing the #define statement.
  72.  
  73.     Some misc. comments on hacking text files with CP/M:
  74.     The conventional CP/M text format calls for each
  75.     line to be terminated by a CR-LF combination. In the
  76.     world of C programming, though, we like to just use
  77.     a single LF (also called a newline) to terminate
  78.     lines. AND SO, the functions which deal with reading
  79.     and writing text from disk files to memory and vice-
  80.     versa ("fgets", "fputs") take special pains to convert
  81.     CR-LF combinations into single '\n' characters when
  82.     reading from disk ("fgets"), and convert '\n' char-
  83.     acters to CR-LF combinations when writing TO disk
  84.     ("fputs"). This allows the C programmer to do things
  85.     in style, dealing only with a single line terminator,
  86.     while maintaining compatibility with the CP/M text
  87.     format (so that, for example, a text file can be
  88.     "type"d under the CCP.)
  89.     To confuse matters further, the "gets" function
  90.     (which simply buffers up a line of console input)
  91.     terminates a line with '\0' (a zero byte) instead
  92.     of CR or LF. Thus, if you wanted to read in lines
  93.     of input from the console and write them to a file,
  94.     you'd have to manually put out the CR and LF at the
  95.     end of every line. Oh, and don't forget the 0x1a
  96.     (control-Z) at the end of the file! Hey, kiddies,
  97.     isn't CP/M fun to work with???
  98.     Also, watch out when reading in text files using
  99.     "getc". While a text file is USUALLY terminated
  100.     with a control-Z, it MAY NOT BE if the file ends
  101.     on an even sector boundary. This means that there
  102.     are two possible return values from "getc" which
  103.     signal and EOF: 0x1a (control-Z), and -1 (or 255
  104.     if you assign it to a char variable.)
  105. */
  106.  
  107.  
  108. #define RAM 0        /* start of CP/M RAM area */
  109. #define MAXLINE 132    /* maximum length of text line */
  110. #define EOF -1        /* End of file val returned by getc */
  111. #define NULL 0        /* Returned by fgets on EOF */
  112.  
  113. char toupper(), isdigit();
  114.  
  115. struct buf {
  116.     int fd;
  117.     int nleft;
  118.     char *nextp;
  119.     char buff[128];
  120.  };
  121.  
  122. /*
  123.     printf
  124.  
  125.     usage:
  126.         printf(format, arg1, arg2, ...);
  127.     
  128.     Note that since the sprintf function is used to
  129.     form the output string and then puts is used to
  130.     actually print it out, care must be taken to 
  131.     avoid generating null (zero) bytes in the output,
  132.     since such a byte will terminate printing of the
  133.     string by puts. Thus, a statment such as:
  134.         printf("%c foo",'\0');
  135.     would print nothing at all.
  136.     See the "sprintf" documentation, below, for more info.
  137. */
  138.  
  139. printf(format)
  140. char *format;
  141. {
  142.     char line[MAXLINE];
  143.     _mvl();
  144.     sprintf(line,format);
  145.     puts(line);
  146. }
  147.  
  148.  
  149. /*
  150.     fprintf:
  151.     Like printf, except that the first argument is
  152.     a pointer to a buffered I/O buffer, and the text
  153.     is written to the file described by the buffer:
  154.     (-1 returned on error)
  155.     usage:
  156.         fprintf(iobuf, format, arg1, arg2, ...);
  157. */
  158.  
  159. fprintf(iobuf,format)
  160. char *format;
  161. struct buf *iobuf;
  162. {
  163.     char text[MAXLINE];
  164.     sprintf(text);
  165.     return fputs(text,iobuf);
  166. }
  167.  
  168.  
  169. /*
  170.     fscanf:
  171.     Like scanf, except that the first argument is
  172.     a pointer to a buffered input file buffer, and
  173.     the text is taken from the file instead of from
  174.     the console.
  175.     Usage:
  176.         fscanf(iobuf, format, ptr1, ptr2, ...);
  177.     Returns number of items matched (zero on EOF.)
  178.     Note that any unprocessed text is lost forever. Each
  179.     time scanf is called, a new line of input is gotten
  180.     from the file, and any information left over from
  181.     the last call is wiped out. Thus, the text in the
  182.     file must be arranged such that a single call to
  183.     fscanf will always get all the required data on a
  184.     line.
  185. */
  186.  
  187. int fscanf(iobuf,format,arg1)
  188. char *format;
  189. struct buf *iobuf;
  190. {
  191.     char text[MAXLINE];
  192.     if (!fgets(text,iobuf)) return 0;
  193.     return sscanf(text,format,arg1);
  194. }
  195.  
  196.  
  197. /*
  198.     scanf:
  199.     This one accepts a line of input text from the
  200.     console, and converts the text to the required
  201.     binary or alphanumeric form (see Kernighan &
  202.     Ritchie for a more thorough description):
  203.     Usage:
  204.         scanf(format, ptr1, ptr2, ...);
  205.     Returns number of items matched.
  206.     Since a new line of text must be entered from the
  207.     console each time scanf is called, any unprocessed
  208.     text left over from the last call is lost forever.
  209.     This is a difference between BDS scanf and UNIX
  210.     scanf. Another is that the field width specification
  211.     is not supported here.
  212. */
  213.  
  214. scanf(format)
  215. char *format;
  216. {
  217.     char line[MAXLINE];
  218.     _mvl();
  219.     gets(line);
  220.     sscanf(line,format);
  221. }
  222.  
  223.  
  224. /*
  225.     Internal function to move all function arguments
  226.     over one place to the right, to make room for
  227.     a new argument in the first position. This is
  228.     necessary so that, for example, "sprintf" can
  229.     be called from within "printf" without clobbering
  230.     one of the arguments. This is NOT a portable
  231.     feature of BDS C, and in fact represents one of
  232.     the biggest kludges in the package. Oh well; live
  233.     and learn.
  234. */
  235.  
  236. _mvl()
  237. {
  238.     int count, *ptr;
  239.     ptr = (RAM + 0x3f7 + 0x2e);
  240.     count = 23;
  241.     while (count--) *ptr = *--ptr;
  242. }
  243.  
  244.  
  245. /*
  246.     sprintf:
  247.     Like fprintf, except a string pointer is specified
  248.     instead of a buffer pointer. The text is written
  249.     to where the string pointer points.
  250.     Usage:
  251.         sprintf(string,format,arg1, arg2, ...);
  252.  
  253.     This is my latest version of the "sprintf" standard library
  254.     routine. This time, folks, it REALLY IS standard. I've
  255.     tried to make it EXACTLY the same as the version presented
  256.     in Kernighan & Ritchie: right-justification of fields is
  257.     now the default instead of left-justification (you can GET
  258.     left-justification by using a dash in the conversion, as
  259.     specified in the book); the "%s" conversion can take a precision
  260.     now as well as a field width; the "e" and "f" conversions, for
  261.     floating point numbers, are supported in a special version of
  262.     "sprintf" given in source form in the FLOAT.C file. If you do
  263.     a lot of number crunching and wish to have that version be the
  264.     default (it eats up a K or two more than this version), just
  265.     replace this version of sprintf in DEFF.CRL with the one in FLOAT.C,
  266.     using the CLIB program, or else be stuck with always typing in
  267.     "float" on the clink command line...
  268. */
  269.  
  270.  
  271. sprintf(line,format)
  272. char *line, *format;
  273. {
  274.     char _uspr(), c, base, *sptr;
  275.     char wbuf[80], *wptr, pf, ljflag;
  276.     int width, precision,  *args;
  277.     char lpadchr;    /* HRM */
  278.  
  279.     args = (RAM + 0x3fb);
  280.     while (c = *format++)
  281.       if (c == '%') {
  282.         wptr = wbuf;
  283.         precision = 6;
  284.         ljflag = pf = 0;
  285.  
  286.         if (*format == '-') {
  287.             format++;
  288.             ljflag++;
  289.          }
  290.  
  291.         if ( !(width = _gv2(&format))) width++;
  292.  
  293.         if ((c = *format++) == '.') {
  294.             precision = _gv2(&format);
  295.             pf++;
  296.             c = *format++;
  297.          }
  298.  
  299.         lpadchr = '0';/* HRM pad char for non-decimal numeric fields */
  300.         switch(toupper(c)) {
  301.  
  302.         case 'D':    lpadchr = ' ';
  303.                 if (*args < 0) {
  304.                 *wptr++ = '-';
  305.                 *args = -*args;
  306.                 width--;
  307.                 }
  308.  
  309.         case 'U':  base = 10; goto val;
  310.  
  311.         case 'B':  base = 2;  goto val;    /* HRM */
  312.  
  313.         case 'X':  base = 16; goto val;
  314.  
  315.         case 'O':  base = 8;
  316.  
  317.              val:  width -= _uspr(&wptr,*args++,base);
  318.                goto pad;
  319.  
  320.         case 'C':  lpadchr = ' ';    /* HRM */
  321.                *wptr++ = *args++;
  322.                width--;
  323.                goto pad;
  324.  
  325.         case 'S': lpadchr = ' ';    /* HRM */
  326.               if (!pf) precision = 200;
  327.                sptr = *args++;
  328.                while (*sptr && precision) {
  329.                 *wptr++ = *sptr++;
  330.                 precision--;
  331.                 width--;
  332.                 }
  333.  
  334.              pad:  *wptr = '\0';
  335.              pad2: wptr = wbuf;
  336.                if (!ljflag)
  337.                 while (width-- > 0)
  338.                     *line++ = lpadchr;    /* HRM mod */
  339.  
  340.                while (*line = *wptr++)
  341.                 line++;
  342.  
  343.                if (ljflag)
  344.                 while (width-- > 0)
  345.                     *line++ = ' ';
  346.                break;
  347.  
  348.          default:  *line++ = c;
  349.  
  350.          }
  351.       }
  352.       else *line++ = c;
  353.  
  354.     *line = '\0';
  355. }
  356.  
  357. /*
  358.     Internal routine used by "sprintf" to perform ascii-
  359.     to-decimal conversion and update an associated pointer:
  360. */
  361.  
  362. int _gv2(sptr)
  363. char **sptr;
  364. {
  365.     int n;
  366.     n = 0;
  367.     while (isdigit(**sptr)) n = 10 * n + *(*sptr)++ - '0';
  368.     return n;
  369. }
  370.  
  371.  
  372. /*
  373.     Internal functio